﻿using System;
using System.Linq;
using System.Web.Mvc;
using ControleRepresentante.Logic;
using ControleRepresentante.Logic.Models;
using ControleRepresentante.Logic.Repositories;
using ControleRepresentante.Logic.Statistics;
using Telerik.Web.Mvc;
using WebSite.Controllers.ControllerExtensions;
using WebSite.ViewModels;
using WebSite.ViewModels.DetailsViewModels;
using WebSite.ViewModels.EditViewModels;
using WebSite.ViewModels.IndexViewModels;

namespace WebSite.Controllers
{
    public class RepresentanteController : CRUDControllerBase<IRepresentanteRepository, Representante, StatisticsBase>
    {
        private readonly IAreaOperacaoRegistry m_AreaOperacaoRegistry;

        public RepresentanteController(IRepositoryProvider repositoryProvider, IAreaOperacaoRegistry areaOperacaoRegistry, ISessionConfiguration sessionConfiguration, IControllerExtensionProvider controllerExtensionProvider)
            : base(repositoryProvider, sessionConfiguration, controllerExtensionProvider)
        {
            m_AreaOperacaoRegistry = areaOperacaoRegistry;
        }

        protected override IIndexViewModel GetIndexViewModel(StatisticsBase statistics)
        {
            return new RepresentanteIndexViewModel();
        }

        protected override EditViewModel GetEditViewModel(Representante model, bool isNew)
        {
            return new RepresentanteEditViewModel();
        }

        protected override DetailsViewModel GetDetailsViewModel(Representante model)
        {
            return new RepresentanteDetailsViewModel();
        }

        protected override void RegisterIndexColumns(IIndexColumnsProvider indexColumnsProvider)
        {
            base.RegisterIndexColumns(indexColumnsProvider);
            indexColumnsProvider.SetDefaultColumns(
                indexColumnsProvider.RegisterColumn("Nome", RepresentanteIndexColumns.Nome),
                indexColumnsProvider.RegisterColumn("Ativo", RepresentanteIndexColumns.Ativo),
                indexColumnsProvider.RegisterColumn("Nº Usuários", RepresentanteIndexColumns.NumeroUsuarios),
                indexColumnsProvider.RegisterColumn("Nº Pedidos", RepresentanteIndexColumns.NumeroPedidos),
                indexColumnsProvider.RegisterColumn("Nº Clientes", RepresentanteIndexColumns.NumeroClientes),
                indexColumnsProvider.RegisterColumn("Nº Vendedores", RepresentanteIndexColumns.NumeroVendedores),
                indexColumnsProvider.RegisterColumn("Nº Fabricas", RepresentanteIndexColumns.NumeroFabricas),
                indexColumnsProvider.RegisterColumn("Nº Transportadoras", RepresentanteIndexColumns.NumeroTransportadoras),
                indexColumnsProvider.RegisterColumn("Ultimo Pedido", RepresentanteIndexColumns.LastPedido),
                indexColumnsProvider.RegisterColumn("Usa Jolitex", RepresentanteIndexColumns.UseJolitex),
                indexColumnsProvider.RegisterColumn("Usa Trivium", RepresentanteIndexColumns.UseTrivium));
        }

        public ActionResult Search()
        {
            return Index();
        }

        [HttpPost]
        public ActionResult Create(string nome, bool ativo, bool useJolitex, bool useTrivium)
        {
            if (TryUpdateRepresentante(nome, ativo, useJolitex, useTrivium))
            {
                try
                {
                    Repository.AddModel(Model);
                    Representante representante = Model;
                    Model = null;
                    return RedirectToAction("Details", representante.Id);
                }
                catch(RepositoryException<RepresentanteError> e)
                {
                    switch (e.Error)
                    {
                        case RepresentanteError.DuplicatedNome:
                            ModelState.AddModelError("Nome", "Nome duplicado");
                            break;
                        default:
                            throw;
                    }
                }
            }
            return Create(false);
        }

        [HttpPost]
        public ActionResult Edit(string nome, bool ativo, bool useJolitex, bool useTrivium)
        {
            if (TryUpdateRepresentante(nome, ativo, useJolitex, useTrivium))
            {
                try
                {
                    Repository.UpdateModel(Model);
                    Guid representanteId = Model.Id;
                    Model = null;
                    return RedirectToAction("Details", representanteId);
                }
                catch (RepositoryException<RepresentanteError> e)
                {
                    switch (e.Error)
                    {
                        case RepresentanteError.DuplicatedNome:
                            ModelState.AddModelError("Nome", "Nome duplicado");
                            break;
                        default:
                            throw;
                    }
                }
            }
            return Edit();
        }

        private bool TryUpdateRepresentante(string nome, bool ativo, bool useJolitex, bool useTrivium)
        {
            Model.Nome = nome;
            Model.Ativo = ativo;
            Model.UseJolitex = useJolitex;
            Model.UseTrivium = useTrivium;

            ModelState.Clear();
            if (String.IsNullOrEmpty(Model.Nome) ||
                Model.Nome.Trim() == String.Empty)
            {
                ModelState.AddModelError("Nome", "*");
            }
            return ModelState.IsValid;
        }

        #region User

        [GridAction]
        public ActionResult UserSelect()
        {
            return GetUsersView();
        }

        [GridAction]
        [HttpPost]
        public ActionResult UserDelete(Guid userId)
        {
            User user = Model.Users.Single(x => x.Id == userId);
            Model.RemoveUser(user);
            return GetUsersView();
        }

        [GridAction]
        [HttpPost]
        public ActionResult UserInsert(string username, string password, string email, bool ativo)
        {
            User user = new User();
            foreach (Area area in AreaOperacaoRegistry.GetAreas())
            {
                Permissao permissao = new Permissao{Area = area};
                foreach (Operacao operacao in m_AreaOperacaoRegistry.GetOperacoes(area))
                {
                    permissao.Operacao |= operacao;
                }
                user.AddPermissao(permissao);
            }
            if (TryUpdateUser(user, username, password, email, ativo))
            {
                Model.AddUser(user);
            }
            return GetUsersView();
        }

        [GridAction]
        [HttpPost]
        public ActionResult UserUpdate(Guid userId, string username, string password, string email, bool ativo)
        {
            User user = Model.Users.Single(x => x.Id == userId);
            TryUpdateUser(user, username, password, email, ativo);
            return GetUsersView();
        }

        private ActionResult GetUsersView()
        {
            return View(new GridModel(Model.Users.Select(x => new UserViewModel(x))));
        }

        private bool TryUpdateUser(User user, string username, string password, string email, bool ativo)
        {
            user.Username = username;
            user.Ativo = ativo;
            user.SetPasswordFromRawText(password);
            user.Email = email;
            IUserRepository userRepository = RepositoryProvider.GetRepository<IUserRepository>();
            return !String.IsNullOrEmpty(user.Username) &&
                   !String.IsNullOrEmpty(password) &&
                   !userRepository.GetAllModels().Any(x => x.Username == username && x.Id != user.Id);
        }

        #endregion
    }
}
